import { State as RootState } from "@/store/root"
import { cart, security } from "@mall/api-services"

import BigDecimal from "decimal.js"
import * as _ from "lodash"
import { ActionContext, Module } from "vuex"

class CartState {
  id = ""
  items: cart.CartItem[] = []
}


const getters = {
  totalPrice: (state: CartState) => {
    return _.chain(state.items)
      .filter(item => item.checked)
      .reduce((total: number, item: cart.CartItem) => {
        return BigDecimal.add(total, BigDecimal.mul(item.price, item.quantity)).toNumber()
      }, 0)
      .value()
  },
  checkedSize: (state: CartState) => {
    return _.chain(state.items).filter(item => item.checked).size().value()
  },
  checkedItems(state: CartState) {
    return _.chain(state.items).filter(item => item.checked).value()
  },
}


class CheckItemPayload {
  public itemId = ""
  public checked = true
}

class AdjustCartItemQuantityPayload {
  public itemId = ""
  public quantityDelta = 0
}

class CheckItemsPayload {
  public itemIds = []
  public checked = true
}

const mutations = {
  adjustCartItemQuantity(state: CartState, payload: AdjustCartItemQuantityPayload) {
    const { itemId, quantityDelta } = payload
    for (const item of state.items) {
      if (item.id === itemId) {
        item.quantity = item.quantity + quantityDelta
      }
    }
  },
  checkItem(state: CartState, payload: CheckItemPayload) {
    const { itemId, checked } = payload
    for (const item of state.items) {
      if (item.id === itemId) {
        item.checked = checked
      }
    }
  },
  checkItems(state: CartState, payload: CheckItemsPayload) {
    const { itemIds, checked } = payload
    for (const itemId of itemIds) {
      for (const item of state.items) {
        if (item.id === itemId) {
          item.checked = checked
          break
        }
      }
    }
  },
  checkAllItems(state: CartState, checked: boolean) {
    _.forEach(state.items, aItem => {
      aItem.checked = checked
    })
  },
  removeItems(state: CartState, itemIds: string[]) {
    state.items = _.filter(state.items, item => !_.includes(itemIds, item.id))
  },
  refresh(state: CartState, cart: cart.Cart) {
    state.id = cart.id
    state.items = cart.items
  },
}

const actions = {
  adjustCartItemQuantity({ commit }: ActionContext<CartState, RootState>, payload: AdjustCartItemQuantityPayload) {
    const customerId = security.SecurityUserHolder.getUserId()
    const adjustment = new cart.CartItemAdjustment()
    adjustment.itemId = payload.itemId
    adjustment.quantityDelta = payload.quantityDelta
    return cart.CartServiceV1.adjustCartItem(customerId, adjustment)
      .then(() => commit("adjustCartItemQuantity", payload))
  },
  checkItem({ commit }: ActionContext<CartState, RootState>, itemId: string) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.checkCartItem(customerId, itemId)
      .then(() => commit("checkItem", { itemId, checked: true }))
  },
  uncheckItem({ commit }: ActionContext<CartState, RootState>, itemId: string) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.uncheckCartItem(customerId, itemId)
      .then(() => commit("checkItem", { itemId, checked: false }))
  },
  checkItems({ commit }: ActionContext<CartState, RootState>, itemIds: string[]) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.checkCartItems(customerId, itemIds)
      .then(() => commit("checkItems", { itemIds, checked: true }))
  },
  uncheckItems({ commit }: ActionContext<CartState, RootState>, itemIds: string[]) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.uncheckCartItems(customerId, itemIds)
      .then(() => commit("checkItems", { itemIds, checked: false }))
  },
  checkAllItems({ commit }: ActionContext<CartState, RootState>) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.checkAllCartItems(customerId)
      .then(() => commit("checkAllItems", true))
  },
  uncheckAllItems({ commit }: ActionContext<CartState, RootState>) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.uncheckAllCartItems(customerId)
      .then(() => commit("checkAllItems", false))
  },
  removeItems({ commit }: ActionContext<CartState, RootState>, itemIds: string[]) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.removeCartItems(customerId, itemIds)
      .then(() => commit("removeItems", itemIds))
  },
  refresh({ commit }: ActionContext<CartState, RootState>) {
    const customerId = security.SecurityUserHolder.getUserId()
    return cart.CartServiceV1.getCart(customerId).then(cart => commit("refresh", cart))
  },
}

export default {
  namespaced: true,
  state: new CartState(),
  actions,
  getters,
  mutations,
} as Module<CartState, RootState>
